﻿
namespace SistemaLogistica.DataAccess
{
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Data.Common;
    using SistemaLogistica.Business.Entities;
    using SistemaLogistica.Business.Entities.Types;

    public class OrdenPedidoData : BaseDataAccess
    {
        private OrdenPedidoData() { }

        private readonly static OrdenPedidoData instancia = new OrdenPedidoData();

        public static OrdenPedidoData Instancia
        {
            get { return instancia; }
        }

        public List<OrdenPedido> Listar()
        {
            List<OrdenPedido> ordenesPedido = new List<OrdenPedido>();
            DbCommand command = db.GetStoredProcCommand("GetAllFromOrdenPedido");

            using (IDataReader dr = db.ExecuteReader(command))
            {
                while (dr.Read())
                {
                    ordenesPedido.Add(new OrdenPedido
                    {
                        IdOrdenPedido = dr.GetInt32(dr.GetOrdinal("IdOrdenPedido")),
                        TipoOrdenPedido = dr.GetInt32(dr.GetOrdinal("TipoOrdenPedido")),
                        Fecha = dr.GetDateTime(dr.GetOrdinal("FechaOrden")),
                        Estado = dr.GetBoolean(dr.GetOrdinal("Estado")),
                        Descripcion = dr.GetString(dr.GetOrdinal("Descripcion")),
                        Pedido = new Pedido
                        {
                            IdPedido = dr.GetInt32(dr.GetOrdinal("IdPedido")),
                            Area = new Area
                            {
                                IdArea = dr.GetInt32(dr.GetOrdinal("IdArea")),
                                Nombre = dr.GetString(dr.GetOrdinal("Nombre"))
                            }
                        },
                        Empleados = new Empleados { IdEmpleado = dr.GetInt16(dr.GetOrdinal("IdEmpleado")) }
                    });
                }
            }
            return ordenesPedido;
        }

        public List<OrdenPedido> ListarPorTipo(PedidoType tipo)
        {
            List<OrdenPedido> ordenesPedido = new List<OrdenPedido>();
            DbCommand command = db.GetStoredProcCommand("GetOrdenPedidoByTipoOrdenPedido");
            db.AddInParameter(command, "tipoOrdenPedido", DbType.Int32, (int)tipo);

            using (IDataReader dr = db.ExecuteReader(command))
            {
                while (dr.Read())
                {
                    ordenesPedido.Add(new OrdenPedido
                    {
                        IdOrdenPedido = dr.GetInt32(dr.GetOrdinal("IdOrdenPedido")),
                        TipoOrdenPedido = dr.GetInt32(dr.GetOrdinal("TipoOrdenPedido")),
                        Fecha = dr.GetDateTime(dr.GetOrdinal("FechaOrden")),
                        Estado = dr.GetBoolean(dr.GetOrdinal("Estado")),
                        Descripcion = dr.GetString(dr.GetOrdinal("Descripcion")),
                        Pedido = new Pedido
                        {
                            IdPedido = dr.GetInt32(dr.GetOrdinal("IdPedido")),
                            Area = new Area
                            {
                                IdArea = dr.GetInt32(dr.GetOrdinal("IdArea")),
                                Nombre = dr.GetString(dr.GetOrdinal("Nombre"))
                            }
                        },
                        Empleados = new Empleados { IdEmpleado = dr.GetInt16(dr.GetOrdinal("IdEmpleado")) }
                    });
                }
            }
            return ordenesPedido;
        }

        public List<OrdenPedido> ListarPorArea(int idArea, bool estado)
        {
            List<OrdenPedido> ordenesPedido = new List<OrdenPedido>();
            DbCommand command = db.GetStoredProcCommand("GetOrdenPedidoByArea");
            db.AddInParameter(command, "idArea", DbType.Int32, idArea);
            db.AddInParameter(command, "estado", DbType.Boolean, estado);

            using (IDataReader dr = db.ExecuteReader(command))
            {
                while (dr.Read())
                {
                    ordenesPedido.Add(new OrdenPedido
                    {
                        IdOrdenPedido = dr.GetInt32(dr.GetOrdinal("IdOrdenPedido")),
                        TipoOrdenPedido = dr.GetInt32(dr.GetOrdinal("TipoOrdenPedido")),
                        Fecha = dr.GetDateTime(dr.GetOrdinal("FechaOrden")),
                        Estado = dr.GetBoolean(dr.GetOrdinal("Estado")),
                        Descripcion = dr.GetString(dr.GetOrdinal("Descripcion")),
                        Pedido = new Pedido
                        {
                            IdPedido = dr.GetInt32(dr.GetOrdinal("IdPedido")),
                            Area = new Area
                            {
                                IdArea = dr.GetInt32(dr.GetOrdinal("IdArea")),
                                Nombre = dr.GetString(dr.GetOrdinal("Nombre"))
                            }
                        },
                        Empleados = new Empleados { IdEmpleado = dr.GetInt16(dr.GetOrdinal("IdEmpleado")) }
                    });
                }
            }
            return ordenesPedido;
        }

        public List<OrdenPedido> Buscar(DateTime fecha)
        {
            List<OrdenPedido> ordenesPedido = new List<OrdenPedido>();
            DbCommand command = db.GetStoredProcCommand("SearchOrdenPedido");
            db.AddInParameter(command, "fecha", DbType.DateTime, fecha);

            using (IDataReader dr = db.ExecuteReader(command))
            {
                while (dr.Read())
                {
                    ordenesPedido.Add(new OrdenPedido
                    {
                        IdOrdenPedido = dr.GetInt32(dr.GetOrdinal("IdOrdenPedido")),
                        TipoOrdenPedido = dr.GetInt32(dr.GetOrdinal("TipoOrdenPedido")),
                        Fecha = dr.GetDateTime(dr.GetOrdinal("FechaOrden")),
                        Estado = dr.GetBoolean(dr.GetOrdinal("Estado")),
                        Descripcion = dr.GetString(dr.GetOrdinal("Descripcion")),
                        Pedido = new Pedido
                        {
                            IdPedido = dr.GetInt32(dr.GetOrdinal("IdPedido")),
                            Area = new Area
                            {
                                IdArea = dr.GetInt32(dr.GetOrdinal("IdArea")),
                                Nombre = dr.GetString(dr.GetOrdinal("Nombre"))
                            }
                        },
                        Empleados = new Empleados { IdEmpleado = dr.GetInt16(dr.GetOrdinal("IdEmpleado")) }
                    });
                }
            }
            return ordenesPedido;
        }

        public OrdenPedido ObtenerPorID(int idOrdenPedido)
        {
            OrdenPedido ordenPedido = null;
            DbCommand command = db.GetStoredProcCommand("GetOrdenPedidoByIdOrdenPedido");
            db.AddInParameter(command, "idOrdenPedido", DbType.Int32, idOrdenPedido);

            using (IDataReader dr = db.ExecuteReader(command))
            {
                if (dr.Read())
                {
                    ordenPedido = new OrdenPedido
                    {
                        IdOrdenPedido = dr.GetInt32(dr.GetOrdinal("IdOrdenPedido")),
                        TipoOrdenPedido = dr.GetInt32(dr.GetOrdinal("TipoOrdenPedido")),
                        Fecha = dr.GetDateTime(dr.GetOrdinal("FechaOrden")),
                        Estado = dr.GetBoolean(dr.GetOrdinal("Estado")),
                        Descripcion = dr.GetString(dr.GetOrdinal("Descripcion")),
                        Pedido = PedidoData.Instancia.ObtenerPorID(dr.GetInt32(dr.GetOrdinal("IdPedido"))),
                        Empleados = new Empleados { IdEmpleado = dr.GetInt16(dr.GetOrdinal("IdEmpleado")) },
                        Detalle = DetalleOrdenPedidoData.Instancia.ListarPorOrdenPedido(idOrdenPedido)
                    };
                }
            }
            return ordenPedido;
        }

        public void Registrar(OrdenPedido orden)
        {
            using (DbConnection conection = db.CreateConnection())
            {
                conection.Open();
                using (DbTransaction transaction = conection.BeginTransaction())
                {
                    try
                    {
                        // INSERTAR ORDEN DE PEDIDO

                        DbCommand cmdOrdenPedido = db.GetStoredProcCommand("InsertOrdenPedido");
                        db.AddInParameter(cmdOrdenPedido, "descripcion", DbType.String, orden.Descripcion);
                        db.AddInParameter(cmdOrdenPedido, "estado", DbType.Boolean, orden.Estado);
                        db.AddInParameter(cmdOrdenPedido, "fechaOrden", DbType.DateTime, orden.Fecha);
                        db.AddInParameter(cmdOrdenPedido, "idEmpleado", DbType.Int16, orden.Empleados.IdEmpleado);
                        db.AddOutParameter(cmdOrdenPedido, "idOrdenPedido", DbType.Int32, 11);
                        db.AddInParameter(cmdOrdenPedido, "idPedido", DbType.Int32, orden.Pedido.IdPedido);
                        db.AddInParameter(cmdOrdenPedido, "tipoOrdenPedido", DbType.Int32, orden.TipoOrdenPedido);

                        int result = db.ExecuteNonQuery(cmdOrdenPedido, transaction);
                        if (result == 0) throw new Exception();

                        int idOrdenPedido = Convert.ToInt32(db.GetParameterValue(cmdOrdenPedido, "idOrdenPedido"));

                        // INSERTAR DETALLE DE ORDEN DE PEDIDO

                        DbCommand cmdDetalleOrden = db.GetStoredProcCommand("InsertDetalleOrdenPedido");
                        db.AddInParameter(cmdDetalleOrden, "cantidad", DbType.Decimal);
                        db.AddInParameter(cmdDetalleOrden, "descripcion", DbType.String);
                        db.AddInParameter(cmdDetalleOrden, "idBien", DbType.Int32);
                        db.AddInParameter(cmdDetalleOrden, "idOrdenPedido", DbType.Int32);

                        foreach (DetalleOrdenPedido d in orden.Detalle)
                        {
                            db.SetParameterValue(cmdDetalleOrden, "cantidad", d.Cantidad);
                            db.SetParameterValue(cmdDetalleOrden, "descripcion", d.Descripcion);
                            db.SetParameterValue(cmdDetalleOrden, "idBien", d.IdBien);
                            db.SetParameterValue(cmdDetalleOrden, "idOrdenPedido", idOrdenPedido);

                            result = db.ExecuteNonQuery(cmdDetalleOrden, transaction);
                            if (result == 0) throw new Exception();
                        }

                        // ACTUALIZAR ESTADO DE ATENCION DE PEDIDO

                        DbCommand cmdPedido = db.GetStoredProcCommand("UpdateEstadoPedido");
                        db.AddInParameter(cmdPedido, "idPedido", DbType.Int32, orden.Pedido.IdPedido);
                        db.AddInParameter(cmdPedido, "estado", DbType.Boolean, true);

                        result = db.ExecuteNonQuery(cmdPedido, transaction);
                        if (result == 0) throw new Exception();

                        // ACTUALIZAR ESTADO DE DETALLE DE PEDIDO

                        DbCommand cmdDetallePedido = db.GetStoredProcCommand("UpdateEstadoDetallePedido");
                        db.AddInParameter(cmdDetallePedido, "idPedido", DbType.Int32);
                        db.AddInParameter(cmdDetallePedido, "idBien", DbType.Int32);
                        db.AddInParameter(cmdDetallePedido, "estado", DbType.Boolean);

                        foreach (DetalleOrdenPedido d in orden.Detalle)
                        {
                            db.SetParameterValue(cmdDetallePedido, "idPedido", orden.Pedido.IdPedido);
                            db.SetParameterValue(cmdDetallePedido, "idBien", d.IdBien);
                            db.SetParameterValue(cmdDetallePedido, "estado", true);

                            result = db.ExecuteNonQuery(cmdDetallePedido, transaction);
                            if (result == 0) throw new Exception();
                        }

                        transaction.Commit();
                    }
                    catch (Exception ex)
                    {
                        transaction.Rollback();
                        throw ex;
                    }
                }
            }
        }

        public void Modificar(OrdenPedido orden)
        {
            using (DbConnection conection = db.CreateConnection())
            {
                conection.Open();
                using (DbTransaction transaction = conection.BeginTransaction())
                {
                    try
                    {
                        // INSERTAR ORDEN DE PEDIDO

                        DbCommand cmdOrdenPedido = db.GetStoredProcCommand("UpdateOrdenPedido");
                        db.AddInParameter(cmdOrdenPedido, "descripcion", DbType.String, orden.Descripcion);
                        db.AddInParameter(cmdOrdenPedido, "estado", DbType.Boolean, orden.Estado);
                        db.AddInParameter(cmdOrdenPedido, "fechaOrden", DbType.DateTime, orden.Fecha);
                        db.AddInParameter(cmdOrdenPedido, "idEmpleado", DbType.Int16, orden.Empleados.IdEmpleado);
                        db.AddInParameter(cmdOrdenPedido, "idOrdenPedido", DbType.Int32, orden.IdOrdenPedido);
                        db.AddInParameter(cmdOrdenPedido, "idPedido", DbType.Int32, orden.Pedido.IdPedido);
                        db.AddInParameter(cmdOrdenPedido, "tipoOrdenPedido", DbType.Int32, orden.TipoOrdenPedido);

                        int result = db.ExecuteNonQuery(cmdOrdenPedido, transaction);
                        if (result == 0) throw new Exception();


                        // ELIMINAR ANTIGUO DETALLE DE ORDEN DE PEDIDO

                        DbCommand cmdEliminar = db.GetStoredProcCommand("DeleteDetalleOrdenPedidoByOrden");
                        db.AddInParameter(cmdEliminar, "idOrdenPedido", DbType.Int32, orden.IdOrdenPedido);

                        result = db.ExecuteNonQuery(cmdEliminar, transaction);
                        if (result == 0) throw new Exception();


                        // INSERTAR DETALLE DE ORDEN DE PEDIDO

                        DbCommand cmdDetalleOrden = db.GetStoredProcCommand("InsertDetalleOrdenPedido");
                        db.AddInParameter(cmdDetalleOrden, "cantidad", DbType.Decimal);
                        db.AddInParameter(cmdDetalleOrden, "descripcion", DbType.String);
                        db.AddInParameter(cmdDetalleOrden, "idBien", DbType.Int32);
                        db.AddInParameter(cmdDetalleOrden, "idOrdenPedido", DbType.Int32);

                        foreach (DetalleOrdenPedido d in orden.Detalle)
                        {
                            db.SetParameterValue(cmdDetalleOrden, "cantidad", d.Cantidad);
                            db.SetParameterValue(cmdDetalleOrden, "descripcion", d.Descripcion);
                            db.SetParameterValue(cmdDetalleOrden, "idBien", d.IdBien);
                            db.SetParameterValue(cmdDetalleOrden, "idOrdenPedido", orden.IdOrdenPedido);

                            result = db.ExecuteNonQuery(cmdDetalleOrden, transaction);
                            if (result == 0) throw new Exception();
                        }


                        // ACTUALIZAR ESTADO DE ATENCION DE PEDIDO

                        DbCommand cmdPedido = db.GetStoredProcCommand("UpdateEstadoPedido");
                        db.AddInParameter(cmdPedido, "idPedido", DbType.Int32, orden.Pedido.IdPedido);
                        db.AddInParameter(cmdPedido, "estado", DbType.Boolean, true);

                        result = db.ExecuteNonQuery(cmdPedido, transaction);
                        if (result == 0) throw new Exception();


                        // REGRESAR AL ESTADO ORIGINAL LOS DETALLES DE PEDIDO

                        DbCommand cmdDetallePedido = db.GetStoredProcCommand("UpdateAllEsatdoDetallePedido");
                        db.AddInParameter(cmdDetallePedido, "idPedido", DbType.Int32, orden.Pedido.IdPedido);
                        db.AddInParameter(cmdDetallePedido, "estado", DbType.Boolean, false);

                        result = db.ExecuteNonQuery(cmdDetallePedido, transaction);
                        if (result == 0) throw new Exception();


                        // ACTUALIZAR ESTADO DE DETALLE DE PEDIDO

                        cmdDetallePedido = db.GetStoredProcCommand("UpdateEstadoDetallePedido");
                        db.AddInParameter(cmdDetallePedido, "idPedido", DbType.Int32);
                        db.AddInParameter(cmdDetallePedido, "idBien", DbType.Int32);
                        db.AddInParameter(cmdDetallePedido, "estado", DbType.Boolean);

                        foreach (DetalleOrdenPedido d in orden.Detalle)
                        {
                            db.SetParameterValue(cmdDetallePedido, "idPedido", orden.Pedido.IdPedido);
                            db.SetParameterValue(cmdDetallePedido, "idBien", d.IdBien);
                            db.SetParameterValue(cmdDetallePedido, "estado", true);

                            result = db.ExecuteNonQuery(cmdDetallePedido, transaction);
                            if (result == 0) throw new Exception();
                        }

                        transaction.Commit();
                    }
                    catch (Exception ex)
                    {
                        transaction.Rollback();
                        throw ex;
                    }
                }
            }
        }

        public void Eliminar(int idOrdenPedido)
        {
            using (DbConnection conection = db.CreateConnection())
            {
                conection.Open();
                using (DbTransaction transaction = conection.BeginTransaction())
                {
                    try
                    {
                        // OBTENER IdPedido DE ORDEN DE PEDIDO

                        int idPedido = ObtenerPorID(idOrdenPedido).Pedido.IdPedido;

                        // ELIMINAR ORDEN DE PEDIDO

                        DbCommand cmdOrdenPedido = db.GetStoredProcCommand("DeleteOrdenPedido");
                        db.AddInParameter(cmdOrdenPedido, "idOrdenPedido", DbType.Int32, idOrdenPedido);

                        int result = db.ExecuteNonQuery(cmdOrdenPedido, transaction);
                        if (result == 0) throw new Exception();

                        // ACTUALIZAR ESTADO DE PEDIDO

                        DbCommand cmdPedido = db.GetStoredProcCommand("UpdateEstadoPedido");
                        db.AddInParameter(cmdPedido, "idPedido", DbType.Int32, idPedido);
                        db.AddInParameter(cmdPedido, "estado", DbType.Boolean, false);

                        result = db.ExecuteNonQuery(cmdPedido, transaction);
                        if (result == 0) throw new Exception();

                        // REGRESAR AL ESTADO ORIGINAL LOS DETALLES DE PEDIDO

                        DbCommand cmdDetallePedido = db.GetStoredProcCommand("UpdateAllEsatdoDetallePedido");
                        db.AddInParameter(cmdDetallePedido, "@idPedido", DbType.Int32, idPedido);
                        db.AddInParameter(cmdDetallePedido, "@estado", DbType.Boolean, false);

                        result = db.ExecuteNonQuery(cmdDetallePedido, transaction);
                        if (result == 0) throw new Exception();

                        transaction.Commit();
                    }
                    catch (Exception ex)
                    {
                        transaction.Rollback();
                        throw ex;
                    }
                }
            }
        }
    }
}
